iT邦幫忙

2024 iThome 鐵人賽

DAY 23
1
JavaScript

可愛又迷人的 Web API系列 第 23

Day23. 深入了解 Intersection Observer API 與其應用 I

  • 分享至 

  • xImage
  •  

今天要分享的是 Intersection Observer API,同樣是 Web Observer 家族 XD,他是用來觀察 DOM 元素與可視區域 (viewport) 或另一個元素之間的相交情況 (intersection)。我們可以監看元素是否進入或退出了可視區域,從而觸發相應的行為。

網路上的範例都是以懶加載 (Lazy Load) 以及無限滾動 (infinite scroll) 居多,我們只要思考一下這兩個技術的實現邏輯,就大概能了解 Intersection Observer API 的監聽方式,核心在於監控元素是否可視區域 (viewport),並根據結果執行特定的操作。

Intersection Observer 的基本用法

跟 MutationObserver API 一樣,我們要先建立一個 Observer 物件,並設定監聽的元素

建立 IntersectionObserver 物件

首先建立 IntersectionObserver 物件。該物件接受一個 callback 和一個可選的 options:

const observer = new IntersectionObserver(callback, options);
  • callback:當目標元素的可見性發生變化時,這個回調函數會被觸發。
  • options:一個可選的配置對象,用來設定 Observer 的行為。

Options 屬性

options 常見的屬性如下:

const options = {
  root: document.querySelector('.scroll-container'),
  rootMargin: '0px',
  threshold: 0.5
};

根元素 (Root)

root 選項用來設置觀察的根元素,如果不設置,默認為視窗可視區域 (viewport)。

const options = {
  root: document.querySelector('.scroll-container'),
  threshold: 0.5
};
const observer = new IntersectionObserver(callback, options);

根元素的邊界 (RootMargin)

rootMargin 可以調整 root 的大小。我們可以擴大或縮小根元素的邊界,從而改變被視為「可見」的區域。使用方式類似 CSS 的 margin 屬性,可以設定四個方向的值,用法與格式也都雷同,例如:rootMargin: '10px 20px 10px 20px',就是上下邊界為 10px,左右邊界為 20 px。

我們還能對 rootMargin 設定正負值,正值會擴大觀察區域,負值會縮小觀察區域。常見的情境如下:

  • 預加載:設置正值可以在元素實際進入可視區域之前就觸發加載。
  • 延遲加載:設置負值可以讓元素更深入可視區域才被認為是可見的。

閾值 (Threshold)

threshold 的意思是閾值,意思是我們要觸發某個變化時,需要滿足某個條件的值,這個值就是閾值 XXD,小時候理化可能有學過(?)。在此就是用來決定目標元素與 DOM 元素或可視區域 (viewport) 相交的比例達到什麼程度時,會觸發 callback。

threshold 的型態是 number,或者可以是一個陣列數字 number[],範圍從 0 到 1,代表目標元素的可見部分比例。

例如:

const options = {
  threshold: [0, 0.5, 1]
};
const observer = new IntersectionObserver(callback, options);

在這個例子中,當目標元素從完全不可見 (0) 到 50% 可見 (0.5),再到完全可見 (1)時,都會執行 callback。

監聽目標元素

接著使用 observe() 方法監聽目標元素:

const target = document.querySelector('.target-element');
observer.observe(target);

以上的程式碼表示,當 .target-element.scroll-container 元素相交時,就會再看 threshold 的設定來決定是否觸發 callback

讓我們把它完整的寫一遍,再加上一些效果:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Intersection Observer Example</title>
  <style>
    /* 設置容器樣式以模擬滾動區域 */
    .scroll-container {
      width: 100%;
      height: 300px;
      overflow-y: scroll;
      border: 1px solid #ccc;
      position: relative;
    }

    /* 設置一個很高的高度來提供滾動空間 */
    .scroll-container::before {
      content: '';
      display: block;
      height: 500px;
    }

    .scroll-container::after {
      content: '';
      display: block;
      height: 500px;
    }

    /* 目標元素樣式 */
    .target-element {
      width: 100px;
      height: 100px;
      background-color: #3498db;
      margin: 20px auto;
      opacity: 0;
      transform: translateY(50px);
      transition: opacity 0.5s ease, transform 0.5s ease;
    }

    /* 當元素進入可視區域時添加的類 */
    .visible {
      opacity: 1;
      transform: translateY(0);
    }
  </style>
</head>
<body>
  
  <div class="scroll-container">
    <div class="target-element"></div>
  </div>
  
  <script>
    const options = {
      root: document.querySelector('.scroll-container'),
      threshold: 0.5
    };
    const observer = new IntersectionObserver(callback, options);

    const target = document.querySelector('.target-element');
    observer.observe(target);

    function callback(entries) {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          entry.target.classList.add('visible');
          console.log('目標元素在可視區域內');
        } else {
          entry.target.classList.remove('visible');
          console.log('目標元素在可視區域外');
        }
      });
    }
  </script>
</body>
</html>

https://mukiwu.github.io/web-api-demo/img/23-1.gif

範例程式碼

https://mukiwu.github.io/web-api-demo/observer.html

小結

透過上面的範例,可以清楚地看出 Intersection Observer API 非常適合做懶加載 (Lazy Load )和無限滾動 (Infinity Scroll) 功能。只需要設定好觀察目標和閾值,就能輕鬆實現所需的效果,無需像過去那樣手動處理座標計算。

以上有任何問題,都歡迎留言討論。


上一篇
Day22. 如何使用 MutationObserver API 追蹤 DOM 的變化 II
下一篇
Day24. 深入了解 Intersection Observer API 與其應用 II
系列文
可愛又迷人的 Web API31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言